from django.db.models import F, Q, Sum
from django.shortcuts import render

# Create your views here.


from booktest.models import BookInfo, HeroInfo

"""新增操作"""
# 增加一本书
# book = BookInfo()
# book.btitle = '红楼梦'
# book.bpub_date = '1991-1-1'
# book.save()

# book = BookInfo(
#     btitle='西游记',
#     bpub_date='1988-1-1',
#     bread=10,
#     bcomment=10,
# )
#
# book.save()


# hero = HeroInfo(
#     hname='孙悟空',
#     hgender=0,
#     hbook=book
# )
# hero.save()

# hero = HeroInfo(
#     hname='猪八戒',
#     hgender=0,
#     hbook_id=book.id
# )
# hero.save()

# 用create创建模型时,不用再调用save,创建的同时直接保存
# HeroInfo.objects.create(
#     hname='沙悟净',
#     hgender=0,
#     hbook=book
# )


"""查询"""
# all
# BookInfo.objects.all()

# get
# try:
#     book = BookInfo.objects.get(btitle='西游记')
# except BookInfo.DoesNotExist:
#     pass

# book = BookInfo.objects.get(btitle='西游记')
# book.id

# BookInfo.objects.get(id=3)
# BookInfo.objects.get(pk=3)

# count
# BookInfo.objects.all().count()

"""过滤查询(重点)"""
# 1.exact：相等
BookInfo.objects.filter(id=1)
BookInfo.objects.filter(id__exact=1)

# 2.模糊查询
# contains：是否包含
# 查询书名包含'传'的图书。
BookInfo.objects.filter(btitle__contains='传')

# startswith、endswith：以指定值开头或结尾。
# 查询书名以'部'结尾的图书
BookInfo.objects.filter(btitle__endswith='部')
# 查询书名以'天'开头的图书
BookInfo.objects.filter(btitle__startswith='天')

# 3.空查询
# isnull：是否为null。
# 查询书名不为空的图书。
BookInfo.objects.filter(btitle__isnull=False)

# 4.多项查询
# 查询编号为1和3和5的图书
BookInfo.objects.filter(id__in=[1, 3, 5])

# 5.比较查询
# gt大于  gte大于等于  lt小于  lte小于等于  不等于的运算符，使用exclude()过滤器。
# 查询编号大于3的图书
BookInfo.objects.filter(id__gt=3)
# 查询编号不等于3的图书
BookInfo.objects.exclude(id=3)

# 6.日期查询
# year、month、day、week_day、hour、minute、second：对日期时间类型的属性进行运算。
# 查询1980年发表的图书。
BookInfo.objects.filter(bpub_date__year=1980)
# 查询1980年1月1日后发表的图书。
BookInfo.objects.filter(bpub_date__gt='1980-1-1')


"""F对象"""
# 使用F对象，被定义在django.db.models中  语法：F(属性名)
# 查询阅读量大于等于评论量的图书。
from django.db.models import F
BookInfo.objects.filter(bread__gte=F('bcomment'))
# 查询阅读量大于2倍评论量的图书。
BookInfo.objects.filter(bread__gte=F('bcomment')*2)

"""Q对象"""
# 1.多个过滤器逐个调用表示逻辑与关系，同sql语句中where部分的and关键字 例如and  or  not
# 查询阅读量大于20，并且编号小于3的图书
BookInfo.objects.filter(bread__gte=20, id__lt=3)
BookInfo.objects.filter(bread__gte=20).filter(id__lt=3)

# 2.实现逻辑或or的查询，需要使用Q()对象结合|运算符，被定义在django.db.models中 语法：Q(属性名__运算符=值)
# 查询阅读量大于20的图书
from django.db.models import Q
BookInfo.objects.filter(Q(bread__gt=20))
# 3.Q对象可以使用&、|连接，&表示逻辑与，|表示逻辑或。
# 查询阅读量大于20，或编号小于3的图书
BookInfo.objects.filter(Q(bread__gt=20) | Q(id__lt=3))
# 4.Q对象前可以使用~操作符，表示非not。
# 查询编号不等于3的图书。
BookInfo.objects.filter(~Q(id=3))

"""聚合函数"""
# 1.使用aggregate()过滤器调用聚合函数。聚合函数包括：Avg 平均，Count 数量，Max 最大，Min 最小，Sum 求和，被定义在django.db.models中。
# 查询图书的总阅读量
from django.db.models import Sum
BookInfo.objects.aggregate(Sum('bread'))
# {'bread__sum': 136} ---> aggregate的返回值是一个字典类型,格式：{'属性名__聚合类小写':值}
# 2.使用count时一般不使用aggregate()过滤器
# 查询图书总数
BookInfo.objects.count()


""" 排序"""
# 使用order_by对结果进行排序
# 升序
BookInfo.objects.all().order_by('bread')
# 降序  order_by('-属性名')
BookInfo.objects.all().order_by('-bread')

"""基本关联查询(重点)"""
# 只要给多的一方指定的外键，那么在一的那方就会隐式生成一个隐藏字段：多的那一方模型名小写_set   heroinfo_set
# 一查多  语法：一对应的模型类对象.多对应的模型类名小写_set
# 多查一 语法：多对应的模型类对象.多对应的模型类中的关系类属性名
"""
一查多:  用book去查hero
第一步先拿到一:book
第二完成一查多: 一的模型实例对象.多的模型名字小写_set  book.heroinfo_set

多查一
第一步先拿到多的这一方的某个模型对象  hero
第二步 hero.hbook
"""
# 一查多 查询id=1的书籍所有英雄
b = BookInfo.objects.get(id=1)
b.heroinfo_set.all()
# 多查一 查询id=1的英雄出自哪一部书
h = HeroInfo.objects.get(id=1)
h.hbook

"""关联过滤查询(重点)"""
# 1.由一模型类条件查询多模型类数据 语法：模型类关联属性名__一模型类属性名__条件运算符=值
# 一查多:  查谁就是谁的模型类对象开头.objects.filter(外键名__属性名__运算符=值)
# 查询书名为“天龙八部”的所有英雄
HeroInfo.objects.filter(hbook__btitle='天龙八部')
# 查询图书阅读量大于30的所有英雄
HeroInfo.objects.filter(hbook__bread__gt=30)

# 2.由多模型类条件查询一模型类数据 语法：关联模型类名小写__属性名__条件运算符=值
# 多查一: 用一这方的模型类对象.objects.filter(多的那一方模型名小写__属性名__运行符=值)
# 查询图书，要求图书英雄为"孙悟空"
BookInfo.objects.filter(heroinfo__hname='孙悟空')
# 查询图书，要求图书中英雄的描述包含"八"
BookInfo.objects.filter(heroinfo__hcomment__contains='八')
# 注：在关联过滤查询时多的一方当条件时,只用写多的一方模型名小写就可以了,不用再加_set
# _set 是在关联基本查询时,用一查多才需要用

"""修改"""
# 1.save
# 修改模型类对象的属性，然后执行save()方法
hero = HeroInfo.objects.get(hname='猪八戒')
hero.hname = '天蓬元帅'
hero.save()

# 2.update
# 使用模型类.objects.filter().update()，会返回受影响的行数
HeroInfo.objects.filter(hname='沙悟净').update(hname='沙僧')


"""删除"""
# 1.模型类对象delete
hero = HeroInfo.objects.get(id=13)
hero.delete()
# 2.模型类.objects.filter().delete()
HeroInfo.objects.filter(id=14).delete()